/*
 * Widget.h
 *
 *	Author: stravant
 *	Description:
 *		
 */

#ifndef WIDGET_H_
#define WIDGET_H_

#include <list>

#include "cairo/cairo.h"

#include "../core/Vec.h"
#include "../core/Rect.h"
#include "../core/RefCounted.h"
#include "../ui/Event.h"

namespace tbt {

class WidgetRoot;
class Window;
namespace fx {class Context; }

class Widget: public RefCounted<Widget> {
public:
	Widget();
	virtual ~Widget();

	/********* properties ******/
	//Active: "Active" GUI elements respond to events, while
	//inactive ones are transparent to them.
	// Default: True
	bool isActive() const {return mActive; }
	void setActive(bool state) {mActive = state; }

	//Visibility: Visible elements are drawn in a redraw, non
	//visible elements are not drawn, and are transparent to
	//events as well.
	// Default: True
	bool isVisible() const {return mVisible; }
	void setVisible(bool state) {mVisible = state; }

	//Transparent: A user-set hint which widgets can use to know
	//when redraw can be ommited. A transparent=false widget
	//gaurantees that it will paint over it's entire area in a
	//repaint cycle.
	bool isTransparent() const {return mTransparent; }
	void setTransparent(bool state) {mTransparent = state; }

	//Size: Current size of the widget
	const IVec& getSize() const {return mBounds.size(); }

	//Position: Current position of the widget
	const IVec& getPosition() const {return mBounds.position(); }

	//Bounds: Size+Position
	const IRect& getBounds() const {return mBounds; }

	//Root: The top of the hierarchy
	Ref<WidgetRoot> getRoot() const;


	/******* root functions ******/
	void captureMouse();
	void releaseMouse();
	void focusKeyboard();
	void blurKeyboard();


	/******* layout *********/
	//For absolute-layout it is also useful to have a desired
	//position for widgets. Non-virtual since a per-class specification
	//of positions is done by the implementation of layout, not an override
	//of getdesiredposition. Defaults to any.
	const IVec& getDesiredPosition() const {return mDesiredPosition; }
	void setDesiredPosition(const IVec& pos) {mDesiredPosition = pos; }
	static const int kPositionAny = -1;

	//Get the desired size of the widget. Widget calculates this
	//value bsed on it's contents and what type of widget it is.
	//By default a set constant desiredsize is provided. Defaults to any;
	virtual IVec getDesiredSize() const {return mDesiredSize; }
	virtual void setDesiredSize(const IVec& size) {mDesiredSize = size; }
	static const int kSizeAny = -1;

	//public access to layout of widget
	//invokes a layout and sets the widget as
	//validly laid out.
	void performLayout();

	//set needs layout
	void invalidate() {mBoundsValid = false; }

	//check needs layout
	bool needsLayout() {return mBoundsValid; }



	/******* rendering info ******/
	void performPaint(const IRect& region, fx::Context* ctx);



	/*********** utils ********/
	//is a point contained in a widget
	virtual bool contains(const IVec& pos) const;

	//find the widget which is at a given point.
	//Uses the following rules:
	//-Visible=false widgets and their children are treated as though
	// they are not there.
	//-Active=false widgets are treated as though they are not there,
	// however their children are considered.
	//-Children are selected before parents.
	//-A child added to a widget later is selected before an object
	// added to a widget sooner (reverse of the draw order).
	//-Candidates for selection are widgets which return true for
	// contains( |pos| )
	Ref<Widget> findWidgetForPoint(const IVec& pos) const;


protected:
	/******* Children *******/
	//All widgets maintain an internal child list for convinience,
	//although the child list is not used by the base widget class
	//it is useful to have as the majority of widgets can act as
	//containers, and some convinence functions are added for
	//common operations on the child list, such as drawing all
	//children or finding the handler for an event.

	//add a child: Not iteration safe
	void addChild(Ref<Widget> child);

	//remove a child: Not iteration safe
	void removeChild(Ref<Widget> child);

	std::list<Ref<Widget>> mChildren;


	/******* internal virtuals *******/
	//Layout the widget according to it's current size / position
	virtual void onLayout();

	//paint a widget
	virtual void onPaint(const IRect& region, fx::Context* ctx);

	//event handlers
	virtual void onEvent_Button(const MouseButtonEvent& e) {}
	virtual void onEvent_Key(const KeyEvent& e) {}
	virtual void onEvent_Scroll(const MouseWheelEvent& e) {}
	virtual void onEvent_Crossing(const MouseEvent& e) {}
	virtual void onEvent_Motion(const MouseEvent& e) {}


	//set size/position, not for public use. Used by container widgets to
	//do layout of their children.
	void setBounds(const IRect& bounds) {mBounds = bounds; }
	void setSize(const IVec& size) {mBounds.setSize(size); }
	void setPosition(const IVec& position) {mBounds.setPosition(position); }

	//so that inhereting classes can still set bounds in a protected way
	void setChildBounds(Ref<Widget> child, const IRect& bounds);


	//set the root widget of a widget
	//works recursively down the widget tree
	void setRoot(Ref<WidgetRoot> root);


private:
	bool mActive;
	bool mVisible;
	bool mTransparent;

	IRect mBounds;
	bool mBoundsValid;

	IVec mDesiredPosition;
	IVec mDesiredSize;

	friend class WidgetRoot;
	friend class Window;
	WidgetRoot* mRoot;
};

}

#endif /* WIDGET_H_ */
















